package com.heima.user.service.impl;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.admin.AdminConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.dtos.AuthDTO;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.user.pojos.ApUserRealname;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.user.dto.CertificationToReturn;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.mapper.ApUserRealnameMapper;
import com.heima.user.service.ApUserRealnameService;
import com.heima.user.utils.YongYouUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


/**
 * @作者 itcast
 * @创建日期 2021/9/20 11:35
 **/
@SuppressWarnings("ALL")
@Service
@Slf4j
public class ApUserRealnameServiceImpl extends ServiceImpl<ApUserRealnameMapper, ApUserRealname> implements ApUserRealnameService {
    @Override
    public ResponseResult loadListByStatus(AuthDTO dto) {
        // 1. 检查参数
        dto.checkParam(); // 分页参数
        // 2. 封装查询条件
        // 2.1  分页条件
        IPage<ApUserRealname> pageReq = new Page<>(dto.getPage(), dto.getSize());
        // 2.2  status
        LambdaQueryWrapper<ApUserRealname> queryWrapper = Wrappers.<ApUserRealname>lambdaQuery();
        // 如果status不为空 按照状态查询
        queryWrapper.eq(dto.getStatus() != null, ApUserRealname::getStatus, dto.getStatus());
        // 3. 执行查询
        IPage<ApUserRealname> pageResult = this.page(pageReq, queryWrapper);
        // 4. 封装结果
        return new PageResponseResult(dto.getPage(), dto.getSize(), pageResult.getTotal(), pageResult.getRecords());
    }

    @Autowired
    ApUserMapper apUserMapper;

    //    @Transactional
    // 开启全局事务
    @GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 100000)
    @Override
    public ResponseResult updateStatusById(AuthDTO dto, Short status) {
        // 1. 检查参数
        // 1.1 检查id
        if (dto.getId() == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "实名认证id不能为空");
        }
        // 1.2 根据id 查询实名认证信息
        ApUserRealname userRealname = getById(dto.getId());
        // 1.3 检查状态  1待审核 2失败 9通过
        if (!userRealname.getStatus().equals(AdminConstants.WAIT_AUTH)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "实名认证状态错误");
        }
        // 1.4 查询关联的apUser信息
        ApUser apUser = apUserMapper.selectById(userRealname.getUserId());
        if (apUser == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "实名认证关联的app用户信息不存在");
        }
        // 2. 修改实名认证的状态
        userRealname.setStatus(status);
        if (StringUtils.isNotBlank(dto.getMsg())) {
            userRealname.setReason(dto.getMsg());
        }
        updateById(userRealname);
        // 3. 判断是否为通过 状态: 9
        if (AdminConstants.PASS_AUTH.equals(userRealname.getStatus())) {
            // 3.1  远程开通自媒体账户
            WmUser wmUser = createWmUser(apUser); // 返回自媒体账户
            // 3.2  创建作者信息  // ap_user   wm_user
            createAuthor(wmUser, apUser);
        }

//        System.out.println(1/0);
        return ResponseResult.okResult();
    }

    @Autowired
    ArticleFeign articleFeign;


    private void createAuthor(WmUser wmUser, ApUser apUser) {
        // 1.  远程查询作者信息是否存在
        ResponseResult<ApAuthor> authorResult = articleFeign.findByUserId(apUser.getId());
        if (authorResult.getCode().intValue() != 0) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, authorResult.getErrorMessage());
        }
        ApAuthor author = authorResult.getData();
        if (author != null) { // 自媒体账户已经有了
            CustException.cust(AppHttpCodeEnum.DATA_EXIST, "对应的作者信息已经存在");
        }
        author = new ApAuthor();
        author.setName(apUser.getName());
        author.setType(2);
        author.setUserId(apUser.getId());
        author.setCreatedTime(new Date());
        author.setWmUserId(wmUser.getId());
        // 2. 如果不存在 ，创建作者信息
        ResponseResult saveResult = articleFeign.save(author);
        if (saveResult.getCode().intValue() != 0) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, saveResult.getErrorMessage());
        }
    }


    @Autowired
    WemediaFeign wemediaFeign;

    /**
     * 远程创建自媒体账户
     *
     * @param apUser
     * @return
     */
    private WmUser createWmUser(ApUser apUser) {
        // 1. 查询关联自媒体账户是否已经创建
        ResponseResult<WmUser> wmUserResult = wemediaFeign.findByName(apUser.getName());
        if (wmUserResult.getCode().intValue() != 0) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, wmUserResult.getErrorMessage());
        }
        WmUser wmUser = wmUserResult.getData();
        if (wmUser != null) { // 自媒体账户已经有了
            CustException.cust(AppHttpCodeEnum.DATA_EXIST, "对应的自媒体账户已经存在");
        }
        wmUser = new WmUser(); // 创建自媒体账户
        wmUser.setApUserId(apUser.getId());
        wmUser.setName(apUser.getName());
        wmUser.setPassword(apUser.getPassword());
        wmUser.setSalt(apUser.getSalt());
        wmUser.setImage(apUser.getImage());
        wmUser.setPhone(apUser.getPhone());
        wmUser.setStatus(9); // 正常
        wmUser.setType(0);
        wmUser.setCreatedTime(new Date());
        ResponseResult<WmUser> saveResult = wemediaFeign.save(wmUser);
        if (saveResult.getCode().intValue() != 0) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, saveResult.getErrorMessage());
        }
        // 2. 创建自媒体账户
        return saveResult.getData();// 已经设置了id的wmUser对象
    }
    @Value("${file.oss.web-site}")
    String webSite;

    @Value("${file.oss.prefix}")
    String prefix;
    //String prefix = null;

    @Autowired
    FileStorageService fileStorageService;



    /**
     * 上传用户身份证图片
     * @param files 上传用户信息的图片
     * @return
     */
    @Override
    public ResponseResult saveIDCardImgInfo(MultipartFile[] files) {
        if(files == null || files.length <1){
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION,"实名认证身份证图片信息不能为空");
//            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"实名认证身份证图片信息不能为空");
        }
        List<String> images = new ArrayList<String>();

        // 用户是否登录 threadlocal.get
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION,"请先登录后再操作");
//            CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"请先登录后再操作");
        }
        ApUserRealname one = getOne(Wrappers.<ApUserRealname>lambdaQuery().eq(ApUserRealname::getUserId, user.getId()));
        if(one != null){
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION,"用户已实名认证");
//            CustException.cust(AppHttpCodeEnum.DATA_EXIST,"用户已实名认证");
        }
        for (MultipartFile file : files) {
            // 1. 检查参数  ( 存在  )    后缀检查: jpg  png   jpeg  gif
            if(file == null ){
                return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION,"请上传正确的文件");
//                CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"请上传正确的文件");
            }

            String imgUrl;
            try {
                String originalFilename = file.getOriginalFilename(); // 原始文件名称   UUID.jpg
                String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
                String uuid = UUID.randomUUID().toString().replaceAll("-", "");// asdsadsad-dfsdfas-asdfasd-dasd
                imgUrl = webSite + fileStorageService.store(prefix, uuid + suffix, file.getInputStream());
                images.add(imgUrl);

            } catch (IOException e) {
                e.printStackTrace();
                CustException.cust(AppHttpCodeEnum.SERVER_ERROR,"服务器出现错误,文件上传失败");
            }
        }
        //前端传入的图片顺序，身份证正面 ==》反面 ==》活体
        ApUserRealname apUserRealname = new ApUserRealname();
        apUserRealname.setUserId(user.getId());
        apUserRealname.setLiveImage(images.get(0));
        apUserRealname.setBackImage(images.get(1));
        apUserRealname.setFontImage(images.get(2));
        apUserRealname.setCreatedTime(new Date());

        // 基于用友云证件OCR功能，解析 身份证正面信息
        CertificationToReturn idCardOcr0 = YongYouUtil.idCardOcr(apUserRealname.getFontImage(), "URL", "0");
        if(!"成功".equals(idCardOcr0.getMessage())){
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION,"证件OCR功能检测验证失败");
        }
        Map<String, String> idCardOcr0List = idCardOcr0.getData();
        if(idCardOcr0List == null && idCardOcr0List.size()==0){
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION,"证件OCR功能检测验证失败,远程调用错误,请重新尝试");
        }
        //获取真实姓名和身份证号
        String name = idCardOcr0List.get("name");;   //真实姓名
        String cardNum = idCardOcr0List.get("cardNum");;    //身份证号
        apUserRealname.setName(name);
        apUserRealname.setIdno(cardNum);;


        //检验
        ResponseResult responseResult = yongYouJianChe(apUserRealname);
        if(responseResult.getCode() != 0){
            return responseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION,responseResult.getErrorMessage());
        }
        //保存数据到数据库
        save(apUserRealname);
        //返回参数
        return ResponseResult.okResult();
    }


    /**
     * 实名认证
     * @param apUserRealname
     * @return
     */
    private static ResponseResult yongYouJianChe(ApUserRealname apUserRealname) {
        //参数检测
        if (apUserRealname == null) {
            log.info("参数出现异常 原因: 参数不存在  参数为:  {}", "ApUserRealname apUserRealname");
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "参数不存在");
        }
        if (apUserRealname.getFontImage() == null) {
            log.info("参数出现异常 原因: 身份证正面图片不存在  用户id:  {}", apUserRealname.getId());
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "身份证正面图片不存在");
        }
        if (apUserRealname.getBackImage() == null) {
            log.info("参数出现异常 原因: 身份证反面图片不存在  用户id:  {}", apUserRealname.getId());
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "身份证反面图片不存在");
        }
        if (apUserRealname.getLiveImage() == null) {
            log.info("参数出现异常 原因: 活体图片不存在  用户id:  {}", apUserRealname.getId());
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "活体图片不存在");
        }
        if (apUserRealname.getName() == null) {
            log.info("参数出现异常 原因: 姓名不存在  用户id:  {}", apUserRealname.getId());
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "姓名不存在");
        }


        //调用用友接口
        //1 基于用友云  身份证号+姓名  认证是否真实  如果通过下一步
        CertificationToReturn twoElementsOfIdCard = YongYouUtil.twoElementsOfIdCard(apUserRealname.getIdno(), apUserRealname.getName());
        String success = twoElementsOfIdCard.getSuccess();
        if (!"true".equals(success)) {
            log.info("二要素验证出现异常 原因: 姓名与身份证不相符或用友云接口调用异常  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "身份证二要素验证失败");
        }
        log.info("=========================二要素验证成功  姓名:{}   身份证号:{}================================", apUserRealname.getName(), apUserRealname.getIdno());


        //2 基于用友云证件OCR功能，解析 正面背面信息  判断身份证有效期 是否过期  通过下一步
        CertificationToReturn idCardOcr0 = YongYouUtil.idCardOcr(apUserRealname.getBackImage(), "URL", "0");
        if (!"成功".equals(idCardOcr0.getMessage())) {
            log.info("OCR验证出现异常 原因: 用友云接口调用异常,证件OCR功能检测验证失败  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "证件OCR功能检测验证失败");
        }
        Map<String, String> idCardOcr0List = idCardOcr0.getData();
        if (idCardOcr0List == null && idCardOcr0List.size() == 0) {
            log.info("OCR验证出现异常 原因: 用友云接口调用异常,证件OCR功能检测验证失败,返回无参数  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "证件OCR功能检测验证失败,远程调用错误,请重新尝试");
        }
        //获取过期时间
        String expiryDate = idCardOcr0List.get("expiryDate");
        try {
            //将字符串转为日期格式
            Date parse = new SimpleDateFormat("yyyyMMdd").parse(expiryDate);
            long time = parse.getTime();
            //获取当前时间
            long time1 = new Date().getTime();
            if (time <= time1) {
                log.info("OCR验证出现异常 原因: 证件OCR功能检测验证失败,身份证过期  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
                return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "身份证过期");
            }
        } catch (ParseException e) {
            log.info("OCR验证出现异常 原因: 证件OCR功能检测验证失败  姓名:{}   身份证号:{}  失败原因:{}", apUserRealname.getName(), apUserRealname.getIdno(), e.getMessage());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "服务器内部错误");
        }
        log.info("=========================OCR验证成功  姓名:{}   身份证号:{}================================", apUserRealname.getName(), apUserRealname.getIdno());


        //3 活体检测检测上传自拍照是否为活体  得到超过80通过下一步
        CertificationToReturn bioassay = YongYouUtil.bioassay(apUserRealname.getLiveImage(), "URL");
        if (!"成功".equals(bioassay.getMessage())) {
            log.info("活体检测验证出现异常 原因: 用友云接口调用异常  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "活体检测验证失败");
        }
        Map<String, String> bioassayList = bioassay.getData();
        if (bioassayList == null && bioassayList.size() == 0) {
            log.info("活体检测验证出现异常 原因: 用友云接口调用异常  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "活体检测验证失败,远程调用错误,请重新尝试");
        }
        String bioassayListScore = bioassayList.get("score");
        if (bioassayListScore != null) {
            float i = Float.parseFloat(bioassayListScore);
            //小于80则检测不通过
            if (i < 80.0) {
                log.info("活体检测验证出现异常 原因: 评分小于80  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
                return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "活体检测验证失败");
            }
        }
        log.info("=========================活体检测验证成功  姓名:{}   身份证号:{}================================", apUserRealname.getName(), apUserRealname.getIdno());


        //4 基于人证核验接口，判断生活照 和 身份证是否为同一人  通过 修改实名认证状态
        CertificationToReturn witnessCheck = YongYouUtil.witnessCheck(apUserRealname.getFontImage(), "URL", apUserRealname.getLiveImage());
        if (!"成功".equals(witnessCheck.getMessage())) {
            log.info("人证核验出现异常 原因: 用友云接口调用异常  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "人证核验验证失败");
        }
        Map<String, String> witnessCheckList = witnessCheck.getData();
        if (witnessCheckList == null && witnessCheckList.size() == 0) {
            log.info("人证核验出现异常 原因: 用友云接口调用异常  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
            return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "人证核验失败,远程调用错误,请重新尝试");
        }

        String witnessCheckListScore = witnessCheckList.get("score");
        if (witnessCheckListScore != null) {
            float i = Float.parseFloat(witnessCheckListScore);
            //小于80则检测不通过
            if (i <= 87.0) {
                log.info("人证核验出现异常 原因: 评分小于80  姓名:{}   身份证号:{}", apUserRealname.getName(), apUserRealname.getIdno());
                return ResponseResult.errorResult(AppHttpCodeEnum.AUTHENTICATION, "人证核验验证失败");
            }
        }
        log.info("=========================人证核验成功  姓名:{}   身份证号:{}================================", apUserRealname.getName(), apUserRealname.getIdno());
        //返回成功信息
        return ResponseResult.okResult();
    }


    /**
     * 测试用友接口main方法
     * @param args
     */
    public static void main(String[] args) {
        ApUserRealname apUserRealname = new ApUserRealname();
        apUserRealname.setFontImage("https://ymnhmtt.oss-cn-shanghai.aliyuncs.com/material/2021/10/20211011/f058469855a247abbe2319d565f6e6dd.jpg");
        apUserRealname.setBackImage("https://ymnhmtt.oss-cn-shanghai.aliyuncs.com/material/2021/10/20211011/95cccb6abc7147a1a9df5192fe02d6b4.jpg");
        apUserRealname.setIdno("350124199511075555");
        apUserRealname.setName("杨铭南");
        apUserRealname.setLiveImage("https://ymnhmtt.oss-cn-shanghai.aliyuncs.com/material/2021/10/20211011/74d5fef89a5040888e086bf7ff97cff6.jpg");
        yongYouJianChe(apUserRealname);
    }
}